package com.example.service.group.service;


import com.example.common.ResponseVO;
import com.example.common.config.AppConfig;
import com.example.common.constant.ConsoleColors;
import com.example.common.constant.Constants;
import com.example.common.enums.command.GroupEventCommand;
import com.example.common.enums.command.MessageCommand;
import com.example.common.model.ClientInfo;
import com.example.common.model.message.GroupChatMessageContent;
import com.example.common.model.message.MessageContent;
import com.example.common.model.message.OfflineMessageContent;
import com.example.pack.message.ChatMessageAck;
import com.example.service.group.model.req.SendGroupMessageReq;
import com.example.service.message.model.resp.SendMessageResp;
import com.example.service.message.service.CheckSendMessageService;
import com.example.service.message.service.MessageStoreService;
import com.example.service.seq.RedisSeq;
import com.example.service.utils.CallbackService;
import com.example.service.utils.MessageProducer;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
import org.springframework.stereotype.Service;

import java.util.List;
import java.util.concurrent.LinkedBlockingDeque;
import java.util.concurrent.ThreadFactory;
import java.util.concurrent.ThreadPoolExecutor;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.atomic.AtomicInteger;

@Service
@Slf4j
public class GroupMessageService {      //群聊消息的验证

    @Autowired
    CheckSendMessageService checkSendMessageService;


    @Autowired
    MessageProducer messageProducer;

    @Autowired
    RedisSeq redisSeq;

    @Autowired
    AppConfig appConfig;

    @Autowired
    CallbackService callbackService;


    @Autowired
    MessageStoreService messageStoreService;


    @Autowired
    ImGroupMemberService imGroupMemberService;


    //初始化线程池
    private final ThreadPoolExecutor threadPoolExecutor;
    {
        final AtomicInteger num = new AtomicInteger(0);
        threadPoolExecutor = new ThreadPoolExecutor(8, 8, 60, TimeUnit.SECONDS,
                new LinkedBlockingDeque<>(1000), new ThreadFactory() {
            @Override
            public Thread newThread(Runnable r) {
                Thread thread = new Thread(r);
                thread.setDaemon(true);
                thread.setName("message-group-thread-" + num.getAndIncrement());
                return thread;
            }
        });
    }


    public void process(GroupChatMessageContent messageContent){

        //前置校验
        //这个用户是否被禁言， 是否禁用
        //发送方是否是好友
        String fromId = messageContent.getFromId();
        String groupId = messageContent.getGroupId();
        Integer appId=messageContent.getAppId();

        //从redis里面查询是否存在这个消息
        GroupChatMessageContent messageFromMessageIdCache = messageStoreService.getMessageFromMessageIdCache(messageContent.getAppId(),
                messageContent.getMessageId(), GroupChatMessageContent.class);

        if(messageFromMessageIdCache !=null){   //这个表示之前处理过 所以把持久化的部分删掉
            threadPoolExecutor.execute(()->{
                //1.回成功的ack给自己
                ack(messageContent);
                //2.发消息给同步在线端
                syncToSender(messageContent,messageContent);
                //3.发消息给对方在线端
                dispatchMessage(messageContent);
            });

        }

        long seq = redisSeq.doGetSeq(messageContent.getAppId() + ":" + Constants.SeqConstants.GroupMessage + messageContent.getGroupId());
        messageContent.setMessageSequence(seq);

            //使用多线程进行处理
            threadPoolExecutor.execute(()->{
                messageStoreService.storeGroupMessage(messageContent);    //进行群聊消息的保存

                //对离线消息的存储
                List<String> groupMemberId = imGroupMemberService.getGroupMemberId(messageContent.getGroupId(), messageContent.getAppId());
                messageContent.setMemberId(groupMemberId);
                OfflineMessageContent offlineMessageContent=new OfflineMessageContent();
                BeanUtils.copyProperties(messageContent,offlineMessageContent);
                offlineMessageContent.setToId(messageContent.getGroupId());
                messageStoreService.storeGroupOfflineMessage(offlineMessageContent,groupMemberId);


                //1.回成功的ack给自己
                ack(messageContent);
                //2.发消息给同步在线端
                syncToSender(messageContent,messageContent);
                //3.发消息给对方在线端
                dispatchMessage(messageContent);
                //在将消息分发完后将消息的id存到redis中
                messageStoreService.setMessageFromMessageIdCache(messageContent.getAppId(),messageContent.getMessageId(),messageContent);
            });



    }


    //ack是客户端返回给消息发送者的 看是消息发送成功还是失败
    private void ack(MessageContent messageContent){
        ChatMessageAck chatMessageAck = new ChatMessageAck(messageContent.getMessageId(),messageContent.getMessageSequence());
        ResponseVO responseVO=new ResponseVO();
        responseVO.setData(chatMessageAck);
        //发消息
        messageProducer.sendToUser(messageContent.getFromId(), GroupEventCommand.GROUP_MSG_ACK,
                responseVO,messageContent
        );
    }

    //进行发消息给其他端
    private void syncToSender(GroupChatMessageContent messageContent, ClientInfo clientInfo){
        messageProducer.sendToUserExceptClient(messageContent.getFromId(),
                GroupEventCommand.MSG_GROUP,messageContent,messageContent);
    }

    //发消息给 消息接收者的所有端
    private void dispatchMessage(GroupChatMessageContent messageContent){
        for (String memberId: messageContent.getMemberId()) {
            if (!memberId.equals(messageContent.getFromId())){     //群内成员需排除自己，因为之前已经通过服务器 发送过了
                messageProducer.sendToUser(memberId, GroupEventCommand.MSG_GROUP,
                        messageContent, messageContent.getAppId());
            }
        }
    }


    //检查群聊消息发送的合法性和发送者的权限的方法
    public ResponseVO imServerPermissionCheck(String fromId, String toId, Integer appId){
        ResponseVO responseVO = checkSendMessageService
                .checkGroupMessage(fromId,toId,appId);
        return responseVO;
    }


    //群聊消息的发送
    public SendMessageResp send(SendGroupMessageReq req) {

        SendMessageResp sendMessageResp = new SendMessageResp();
        GroupChatMessageContent message = new GroupChatMessageContent();
        BeanUtils.copyProperties(req,message);

        messageStoreService.storeGroupMessage(message);

        sendMessageResp.setMessageKey(message.getMessageKey());
        sendMessageResp.setMessageTime(System.currentTimeMillis());
        //2.发消息给同步在线端
        syncToSender(message,message);
        //3.发消息给对方在线端
        dispatchMessage(message);

        return sendMessageResp;

    }



}
